package com.helloniu.fl.upload {

import com.helloniu.fl.ByteWebHandler;
import com.helloniu.fl.util.Tool;
import flash.events.*;
import flash.net.*;
import flash.utils.ByteArray;

public class FileBlockUploaderThread {
    public function FileBlockUploaderThread(ablockInfo:BlockInfo = null, athreadID:int = 0) {
        this.blockInfo = ablockInfo;
        this.threadID = athreadID;
    }

    /**
     * Set upload url.
     */
    public function setUploadURL(auploadURL:String):void {
        this.uploadURL = auploadURL;
    }

    /**
     * Get upload url.
     */
    public function getUploadURL():String {
        return this.uploadURL;
    }

    /**
     * Set file md5 id.
     */
    public function setFileMD5ID(afileMD5ID:String):void {
        this.fileMD5ID = afileMD5ID;
    }

    /**
     * Get file reference.
     */
    public function getFileMD5ID():String {
        return this.fileMD5ID;
    }

    /**
     * Set uploaded data length.
     */
    private function setUploadedTotal(auploadTotal:uint):void {
        uploadTotal = auploadTotal;
    }

    /**
     * Get uploaded data length.
     */
    public function getUploadedTotal():uint {
        return uploadTotal;
    }

    /**
     * Set file upload state.
     */
    private function setState(astate:Number):void {
        state = astate;
    }

    /**
     * Get file upload state.
     */
    public function getState():Number {
        return state;
    }

    /**
     * Set upload data block size.
     */
    public function setDataBlockSize(adataBlockSize:int):void {
        dataBlockSize = adataBlockSize;
    }

    /**
     * Get file upload state.
     */
    public function getDataBlockSize():int {
        return dataBlockSize;
    }

    public function startUpload(acallback:Function = null):void {
        this.callback = acallback;

        uploadTotal = 0
        init(blockInfo);
    }

    private function init(blockInfo:BlockInfo):void  {
        this.startPos = blockInfo.startPos;
        this.endPos = blockInfo.endPos;
        this.currPos = blockInfo.startPos;

        this.blockData = blockInfo.blockData;

        uploadFileBlock();
    }

    /**
     * Upload a data block of the file.
     */
    private function uploadFileBlock():void {
        if(currPos == (endPos + 1)) {
            return;
        }

        var barr:ByteArray = new ByteArray();
        var header:String = "UploadFile";
        // write header
        Tool.writeString(barr, header);
        // write fileMD5ID
        Tool.writeString(barr, fileMD5ID);
        // thread id
        barr.writeInt(threadID);
        // write endPos
        Tool.writeLong(barr, endPos);

        // write curr pos
        Tool.writeLong(barr, currPos);

        if((currPos + dataBlockSize) <= (endPos + 1)) {
            barr.writeInt(dataBlockSize);

            blockData.position = currPos - startPos;
            blockData.readBytes(barr, barr.position, dataBlockSize); // file block data
        }
        else {
            var lastDataBlockSize:int = endPos - currPos + 1;
            barr.writeInt(lastDataBlockSize);

            blockData.position = currPos - startPos;
            blockData.readBytes(barr, barr.position, lastDataBlockSize); // file block data
        }

        handler.setReqURL(uploadURL);
        handler.setReqData(barr);
        handler.executeCommunication(uploadFileBlockOver);
    }

    private function uploadFileBlockOver(ahandler:ByteWebHandler):void {
        if(ahandler.getState() != ByteWebHandler.COMMUNICATION_SUCCESSFUL) {
            setState(ByteWebHandler.COMMUNICATION_FAILED);
            processOver();
            return;
        }

        // success
        if((currPos + dataBlockSize) <= (endPos + 1)) {
            //uploadTotal += dataBlockSize;
            uploadTotal = dataBlockSize;
            currPos += dataBlockSize;

        }
        else {
            //uploadTotal += endPos - currPos + 1;
            uploadTotal = endPos - currPos + 1;
            currPos = endPos + 1;
        }

        setState(ByteWebHandler.COMMUNICATION_SUCCESSFUL);
        processOver();

        if(paused) {
            return;
        }

        uploadFileBlock();
    }

    /**
     * One process executing over.
     */
    private function processOver():void {
        if(callback != null) {
            (callback as Function).call(null, this);
        }
    }

    public function pause():void {
        paused = true;
    }

    public function resume():void {
        paused = false;

        uploadFileBlock();
    }

    private var blockInfo:BlockInfo;
    private var startPos:uint;
    private var endPos:uint;
    private var currPos:uint;
    private var blockData:ByteArray;
    private var threadID:int;

    private var uploadTotal:uint = 0; // get, 已经上传字节数
    private var callback:Function;
    private var state:Number; // get， 上传状态

    private var fileMD5ID:String
    private var dataBlockSize:int = 1024;

    private var uploadURL:String
    private var handler:ByteWebHandler = new ByteWebHandler();

    private var paused:Boolean = false; // controller
}
}